/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package clusterAnalysis;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import utils.FileUtils;
import utils.Handle;
import utils.fishersExact.FishersExactTest;

/**
 *
 * @author jamie
 */
public class HIVProtInteractionStats {
    
    private TreeMap<Integer, List<Integer>> geneMap;
    private TreeMap<String, List<Integer>> hivProtInteractions;
    private TreeMap<String, List<Integer>> interactionTypes;
    private TreeMap<String, List<Integer>> hivProtInteractionTypes;
    private Collection<Integer> geneUniverse;
    private boolean regulatesOnly =false;
    private int minimumRepresentation = 2;
    private double minFC=0;

    private File outputFolder = new File("/Users/jamie/Dropbox/monkeys/clust/stats/");

    public HIVProtInteractionStats(TreeMap<Integer, List<Integer>> geneMap) {
        this.geneMap = geneMap;
        Handle handle = Handle.getConnectedHandle("hiv_interactions");
        hivProtInteractions = getHivProtInteractions(handle);
        interactionTypes = getInteractionTypes(handle);
        hivProtInteractionTypes = getHivProtInteractionTypes(handle);

        geneUniverse = getGeneUniverse(hivProtInteractions.values());
        calculateHivProtOverrepresentation();
//        calculateInteractionTypeOverrepresentation();
        calculateHivProtInteractionTypeOverrepresentation();
    }

    private void calculateHivProtOverrepresentation(){
        for(Map.Entry<Integer, List<Integer>> entry : geneMap.entrySet()){
            calculateHivProtOverrepresentation(entry.getKey(), entry.getValue());

        }
    }

    private void calculateHivProtOverrepresentation(int clusterId, List<Integer> geneIds){
        for(String hivProt : hivProtInteractions.keySet()){
            List<Integer> intersection = new ArrayList<Integer>();
            intersection.addAll(geneIds);
            intersection.retainAll(hivProtInteractions.get(hivProt));
            geneIds = filterForHivInteracting(geneIds);
            if(intersection.size()>=minimumRepresentation){
                
                double fc = getFoldEnrichment(geneUniverse.size(), hivProtInteractions.get(hivProt).size(), geneIds.size(), intersection.size());
                if(minFC<fc){
                    FishersExactTest fet = new FishersExactTest(geneUniverse.size(), hivProtInteractions.get(hivProt).size(), geneIds.size(), intersection.size());
                    System.out.println(clusterId+"\t"+hivProt+"\t"+geneUniverse.size()+"\t"+hivProtInteractions.get(hivProt).size()+"\t"+geneIds.size()+"\t"+intersection.size()+"\t"+fet.getResult()+"\t"+fc);
                    
                }
            }
        }
    }

//    private void calculateInteractionTypeOverrepresentation(){
//        for(Map.Entry<Integer, List<Integer>> entry : geneMap.entrySet()){
//            calculateInteractionTypeOverrepresentation(entry.getKey(), entry.getValue());
//
//        }
//    }

//    private void calculateInteractionTypeOverrepresentation(int clusterId, List<Integer> geneIds){
//        for(String type : interactionTypes.keySet()){
//            List<Integer> intersection = new ArrayList<Integer>();
//            intersection.addAll(geneIds);
//            intersection.retainAll(interactionTypes.get(type));
//            if(intersection.size()>=minimumRepresentation){
//
//                double fc = getFoldEnrichment(geneUniverse.size(), interactionTypes.get(type).size(), geneIds.size(), intersection.size());
//                if(minFC<fc){
//                    FishersExactTest fet = new FishersExactTest(geneUniverse.size(), interactionTypes.get(type).size(), geneIds.size(), intersection.size());
//                    System.out.println(clusterId+"\t"+type+"\t"+intersection.size()+"\t"+fet.getResult()+"\t"+fc);
//                }
//            }
//        }
//    }

    private void calculateHivProtInteractionTypeOverrepresentation(){
        BufferedWriter writer = FileUtils.getBufferedWriter(new File(outputFolder, "hivProtInteractionTypes.txt"));
        for(Map.Entry<Integer, List<Integer>> entry : geneMap.entrySet()){
            try {
                calculateHivProtInteractionTypeOverrepresentation(entry.getKey(), entry.getValue(), writer);
            } catch (IOException ex) {
                Logger.getLogger(HIVProtInteractionStats.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        try {
            writer.close();
        } catch (IOException ex) {
            Logger.getLogger(HIVProtInteractionStats.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void calculateHivProtInteractionTypeOverrepresentation(int clusterId, List<Integer> geneIds, BufferedWriter writer) throws IOException{
        for(String type : hivProtInteractionTypes.keySet()){
            geneIds = filterForHivInteracting(geneIds);
            List<Integer> intersection = new ArrayList<Integer>();
            intersection.addAll(geneIds);
            intersection.retainAll(hivProtInteractionTypes.get(type));
            if(intersection.size()>=minimumRepresentation){
                
                double fc = getFoldEnrichment(geneUniverse.size(), hivProtInteractionTypes.get(type).size(), geneIds.size(), intersection.size());
                if(minFC<fc){
                    FishersExactTest fet = new FishersExactTest(geneUniverse.size(), hivProtInteractionTypes.get(type).size(), geneIds.size(), intersection.size());
                    System.out.println(clusterId+"\t"+type+"\t"+geneUniverse.size()+"\t"+hivProtInteractionTypes.get(type).size()+"\t"+geneIds.size()+"\t"+intersection.size()+"\t"+fet.getResult()+"\t"+fc);

                    writer.append(clusterId + "\t" + type + "\t" + intersection.size() + "\t" + fc + "\t"+fet.getResult() + "\n");
                    
                }
            }
        }
        
        
        
    }

    private TreeMap<String, List<Integer>> getHivProtInteractions(Handle handle) {
        String sql = "select distinct name_1, gId_2 from hiv_interactions order by name_1, gId_2";
        if(regulatesOnly==true){
            sql = "select distinct name_1, gId_2 from hiv_interactions where (interaction = 'regulates' || interaction = 'upregulates' || interaction = 'downregulates') order by name_1, gId_2 ";
        }
        ResultSet rs = handle.runSQLquery(sql);
        TreeMap<String, List<Integer>> data = new TreeMap<String, List<Integer>>();
        try {
            while (rs.next()) {
                String hivProt = rs.getString("name_1");
                int gId = rs.getInt("gId_2");
                if(!data.containsKey(hivProt)){
                    data.put(hivProt, new ArrayList<Integer>());
                }
                data.get(hivProt).add(gId);
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(HIVProtInteractionStats.class.getName()).log(Level.SEVERE, null, ex);
        }
        return data;
    }

    private TreeMap<String, List<Integer>> getInteractionTypes(Handle handle) {
        String sql = "select distinct interaction, gId_2 from hiv_interactions order by name_1, gId_2";
        if(regulatesOnly==true){
            sql = "select distinct interaction, gId_2 from hiv_interactions where (interaction = 'regulates' || interaction = 'upregulates' || interaction = 'downregulates') order by interaction, gId_2 ";
        }
        ResultSet rs = handle.runSQLquery(sql);
        TreeMap<String, List<Integer>> data = new TreeMap<String, List<Integer>>();
        try {
            while (rs.next()) {
                String interactionType = rs.getString("interaction");
                int gId = rs.getInt("gId_2");
                if(!data.containsKey(interactionType)){
                    data.put(interactionType, new ArrayList<Integer>());
                }
                data.get(interactionType).add(gId);
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(HIVProtInteractionStats.class.getName()).log(Level.SEVERE, null, ex);
        }
        return data;
    }

    private TreeMap<String, List<Integer>> getHivProtInteractionTypes(Handle handle) {
        String sql = "select distinct name_1, interaction, gId_2 from hiv_interactions order by name_1, interaction, gId_2";
        if(regulatesOnly==true){
            sql = "select distinct name_1, interaction, gId_2 from hiv_interactions where (interaction = 'regulates' || interaction = 'upregulates' || interaction = 'downregulates') order by name_1, interaction, gId_2 ";
        }
        ResultSet rs = handle.runSQLquery(sql);
        TreeMap<String, List<Integer>> data = new TreeMap<String, List<Integer>>();
        try {
            while (rs.next()) {
                String hivProtInteractionTpe = rs.getString("name_1")+"_"+rs.getString("interaction");
                int gId = rs.getInt("gId_2");
                if(!data.containsKey(hivProtInteractionTpe)){
                    data.put(hivProtInteractionTpe, new ArrayList<Integer>());
                }
                data.get(hivProtInteractionTpe).add(gId);
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(HIVProtInteractionStats.class.getName()).log(Level.SEVERE, null, ex);
        }
        return data;
    }

    private Set<Integer> getGeneUniverse(Collection<List<Integer>> values1) {
        Set<Integer> all = new HashSet<Integer>();
        for(List<Integer> list : values1){
            for(int id : list){
                if(!all.contains(id)){
                    all.add(id);
                }
            }
        }
        return all;
    }

//    private Set<Integer> getGeneUniverse(Collection<List<Integer>> values1, Collection<List<Integer>> values2) {
//        Set<Integer> all = new HashSet<Integer>();
//        for(List<Integer> list : values1){
//            for(int id : list){
//                if(!all.contains(id)){
//                    all.add(id);
//                }
//            }
//        }
//        for(List<Integer> list : values2){
//            for(int id : list){
//                if(!all.contains(id)){
//                    all.add(id);
//                }
//            }
//        }
//        return all;
//    }

    private double getFoldEnrichment(int popsize, int popsuc, int samsize, int samsuc){
       double expected = (popsuc+0.0)/popsize;
       double actual = (samsuc+0.0)/samsize;
       return actual/expected;
    }

    private List<Integer> filterForHivInteracting(List<Integer> geneIds) {
        List<Integer> filteredGeneIds = new ArrayList<Integer>();
        for(int gId : geneIds){
            if(geneUniverse.contains(gId)){
                filteredGeneIds.add(gId);
            }
        }
        return filteredGeneIds;
    }



}
